package com.tangsm.spring.boot.degradation.util;

import com.tangsm.spring.boot.degradation.annotation.ResourceDegradation;
import org.reflections.Reflections;
import org.reflections.scanners.MethodAnnotationsScanner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 *
 * @author TanSM
 */
public enum ResourceDowngradeUtil {

    /**
     * 单列
     */
    INSTANCE;

    private Logger log = LoggerFactory.getLogger(this.getClass());

    public static final String packageName = "com.tangsm.spring.boot.degradation.service";

    public static final String MAX_THRESHOLD_KEY = "maxThreshold";

    private Map<String, ResourceDegradation> resouceId2AnnotaionMap = new ConcurrentHashMap<>();

    public void init() {
        Reflections reflections = new Reflections(packageName, new MethodAnnotationsScanner());
        Set<Method> methodSet = reflections.getMethodsAnnotatedWith(ResourceDegradation.class);
        if (!CollectionUtils.isEmpty(methodSet)) {
            for (Method method : methodSet) {
                ResourceDegradation resourceDegradation = method.getAnnotation(ResourceDegradation.class);
                resouceId2AnnotaionMap.put(resourceDegradation.resourceId(), resourceDegradation);
            }
        }

    }

    public ResourceDegradation getResouceDowngradeByResouceId(String resouceId) {
        ResourceDegradation resourceDegradation = resouceId2AnnotaionMap.get(resouceId);
        Assert.notNull(resourceDegradation, " resouceId : " + resouceId + " can not found resourceDegradation");
        return resourceDegradation;
    }


    public void changeThreshold(String resouceId, Integer threshold) {
        ResourceDegradation resourceDegradation = this.getResouceDowngradeByResouceId(resouceId);
        InvocationHandler invocationHandler = Proxy.getInvocationHandler(resourceDegradation);
        try {
            Field field = invocationHandler.getClass().getDeclaredField("memberValues");
            field.setAccessible(true);
            Map<String, Object> memberValues = (Map<String, Object>) field.get(invocationHandler);
            if (memberValues.containsKey(MAX_THRESHOLD_KEY)) {
                memberValues.put(MAX_THRESHOLD_KEY, threshold);
                log.info("resouceId: {} change maxThreshold to {} ok !", resouceId, threshold);
            }
        } catch (NoSuchFieldException | IllegalAccessException e) {
            log.error("changeThreshold error:" + e.getMessage(), e);
        }
    }
}
